package com.gongj.spring;

import com.gongj.spring.annotation.Component;
import com.gongj.spring.annotation.ComponentScan;
import com.gongj.spring.annotation.Lazy;
import com.gongj.spring.annotation.Scope;
import com.gongj.spring.core.BeanDefinition;
import com.gongj.spring.enums.ScopeEnum;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public class Application {

    private Class configClass;

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    // 单例池
    private Map<String, Object> singletonBeanMap = new HashMap<>();

    public Application(Class configClass) {
        this.configClass = configClass;
        //扫描 得到BeanDefinition对象
        scan(configClass);
        //创建非懒加载的单例bean
        createNoLazySingleton();
    }

    private void createNoLazySingleton() {
        Set<String> keySet = beanDefinitionMap.keySet();
        for (String beanName : keySet) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //作用域为singleton并且非懒加载
            if(ScopeEnum.singleton.toString().equals(beanDefinition.getScope()) && !beanDefinition.getLazy()){
                //创建Bean
                Object bean = createBean(beanDefinition);
                //将创建的Bean放入单例池
                singletonBeanMap.put(beanName,bean);
            }
        }
    }

    private Object createBean(BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();
        try {
            //获得实例
            Object o = clazz.getDeclaredConstructor().newInstance();
            return o;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void scan(Class configClass) {
        //类上是否包含ComponentScan该注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //获得扫描路径
            String path = componentScanAnnotation.value();
            System.out.println("扫描路径 = " + path);
            //默认是ApplicationClassLoader进行加载
            ClassLoader classLoader = Application.class.getClassLoader();
            path = path.replace(".", "/");
            URL resource = classLoader.getResource(path);
            //获得target/classes目录下的class文件
            File file = new File(resource.getFile());
            for (File listFile : file.listFiles()) {
                //实例:D:\gongj\spring-work\spring\target\classes\com\gongj\spring\service\UserService.class
                String absolutePath = listFile.getAbsolutePath();
                if(absolutePath.endsWith(".class")){
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\\",".");
                    try {
                        Class clazz = classLoader.loadClass(absolutePath);
                        System.out.println("获得的类对象 ： "+ clazz);
                        //代表这是需要我们生成Bean对象
                        if (clazz.isAnnotationPresent(Component.class)) {
                            Component componentAnnotation = (Component)clazz.getAnnotation(Component.class);
                            String beanName = componentAnnotation.value();
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setClazz(clazz);
                            if(clazz.isAnnotationPresent(Lazy.class)){
                                //这是一个懒加载的Bean 需要等到使用时 才创建
                                beanDefinition.setLazy(true);
                            }
                            if(clazz.isAnnotationPresent(Scope.class)){
                                Scope scopeAnnotation = (Scope) clazz.getAnnotation(Scope.class);
                                if(ScopeEnum.prototype.toString().equals(scopeAnnotation.value())){
                                    //原型bean 每次使用时创建
                                    beanDefinition.setScope(ScopeEnum.prototype.toString());
                                }else{
                                    //单例bean 从单例池中获取
                                    beanDefinition.setScope(ScopeEnum.singleton.toString());
                                }
                            }else{
                                //设置作用域默认值为单例singleton
                                beanDefinition.setScope(ScopeEnum.singleton.toString());
                            }
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        System.out.println("类不存在 ===>" + e);
                    }

                }
            }
        }
    }

    public Object getBean(String beanName) {
        if(!beanDefinitionMap.containsKey(beanName)){
            throw new NullPointerException();
        }else{
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if(ScopeEnum.singleton.toString().equals(beanDefinition.getScope())){
                Object o = singletonBeanMap.get(beanName);
                //懒加载
                if(Objects.isNull(o)){
                    createBean(beanDefinition);
                }
                return o;
            }else if(ScopeEnum.prototype.toString().equals(beanDefinition.getScope())){
                Object bean = createBean(beanDefinition);
                return bean;
            }
        }
        return null;
    }
}
